//
// Copyright (c) 2009 All Right Reserved
//
// vl
//
// 2009-01-01
// Contains ...
namespace LargoCommon.Music
{
using Abstract;
using JetBrains.Annotations;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Xml.Linq;
///
/// Harmonic Streams Port.
///
public class MusicalOrchestration
{
#region Constructors
///
/// Initializes a new instance of the class.
///
public MusicalOrchestration() {
this.OrchestraBlocks = new List();
}
///
/// Initializes a new instance of the class.
///
/// The given block.
public MusicalOrchestration(MusicalBlock givenBlock) {
this.ObjectName = givenBlock.FullName;
this.Header = givenBlock.Header;
this.OrchestraBlocks = new List();
var body = givenBlock.Body;
//// ?!?!?! body.SetHarmonicBasis(this.BlockChanges); //// true
var simpleChanges = body.ExtractSimpleChanges(MusicalChangeType.Instrument);
//// var simpleChanges = this.BlockChanges.InstrumentChanges;
var changedBarNumbers = (from ic in simpleChanges select ic.BarNumber).Distinct().ToList();
OrchestraBlock lastOrchestraBlock = null;
var changedBars = from b in body.Bars where changedBarNumbers.Contains(b.BarNumber) select b;
foreach (var bar in changedBars) {
if (lastOrchestraBlock != null) {
lastOrchestraBlock.BarNumberTo = bar.BarNumber - 1;
}
var strip = bar.OrchestraStrip();
var orchestraBlock = new OrchestraBlock(givenBlock.Header, bar.BarNumber, strip);
this.OrchestraBlocks.Add(orchestraBlock);
lastOrchestraBlock = orchestraBlock;
}
if (lastOrchestraBlock != null) {
lastOrchestraBlock.BarNumberTo = givenBlock.Header.NumberOfBars;
}
}
#endregion
#region Public properties
///
/// Gets or sets the header.
///
///
/// The header.
///
public MusicalHeader Header { get; set; }
///
/// Gets or sets the name of the style.
///
///
/// The name of the set.
///
public string ObjectName { get; set; }
///
/// Gets a value indicating whether is valid.
///
///
/// true if this instance is valid; otherwise, false.
///
[UsedImplicitly]
public bool IsValid => this.OrchestraBlocks.Any();
///
/// Gets or sets the instrumentation of bars.
///
///
/// Property description.
///
public IList OrchestraBlocks { get; set; }
#endregion
#region Public static factory methods
#endregion
///
/// Orchestrates the specified given block.
///
/// The given block.
/// The area.
/// The orchestra block.
public static void Orchestrate(MusicalBlock givenBlock, MusicalSection area, OrchestraBlock orchestraBlock) {
int line = -1;
foreach (var mtrack in givenBlock.Strip.Lines) {
line++;
if (mtrack == null) {
continue;
}
var track = orchestraBlock.Strip.OptimalOrchestraTrack(mtrack);
if (track == null) {
continue;
}
if (mtrack.FirstStatus != null) {
mtrack.FirstStatus.CurrentOrchestraTrack = track;
}
if (mtrack.FirstStatus != null) {
mtrack.FirstStatus.Instrument = track.Instrument;
}
var tones = mtrack.MusicalTonesInArea(area);
tones.SetInstrument(track.InstrumentNumber, track.Octave);
for (var bar = 1; bar <= givenBlock.Header.NumberOfBars; bar++) {
var point = MusicalPoint.GetPoint(line, bar); //// 2017/03 !?!?
//// var point = MusicalPoint.GetPoint(mtrack.LineIndex, bar); //// line
var me = givenBlock.Body.GetElement(point);
if (me == null) {
continue;
}
me.Status.Instrument = track.Instrument;
}
track.IsUsed = true;
}
}
#region String representation
/// String representation of the object.
/// Returns value.
public override string ToString() {
var s = new StringBuilder();
s.AppendFormat("Orchestra {0}", this.ObjectName);
return s.ToString();
}
#endregion
#region Public methods
///
/// Adds the content of the style.
///
/// The orchestration.
[UsedImplicitly]
public void AddObjectContent(MusicalOrchestration orchestration) {
//// this = style.HarmonicOrder; this.RhythmicOrder = style.RhythmicOrder; //// ???????
var ob = (List)this.OrchestraBlocks;
ob.AddRange(orchestration.OrchestraBlocks);
}
///
/// Saves the style.
///
/// The given folder.
[UsedImplicitly]
public void SaveToFolder(string givenFolder) {
var tmpFolderPath = SupportFiles.GetTemporaryDirectory;
Directory.CreateDirectory(tmpFolderPath);
XElement xcomponent = new XElement(
"Component",
new XAttribute("Description", string.Empty),
new XAttribute("Name", this.ObjectName),
this.Header.GetXElement);
var xdoc = new XDocument(new XDeclaration("1.0", "utf-8", null), xcomponent);
xdoc.Save(Path.Combine(tmpFolderPath, @"Component.xml"));
//// Orchestra Blocks
var xblocks = this.WriteOrchestraBlocks();
xdoc = new XDocument(new XDeclaration("1.0", "utf-8", null), xblocks);
//// var filepath = Path.Combine(givenPath, "RhythmicPatterns.xml");
xdoc.Save(Path.Combine(tmpFolderPath, @"OrchestraBlocks.xml"));
var finalPath = Path.Combine(givenFolder, this.ObjectName.ClearSpecialChars() + ".orchestra");
ZipFile.CreateFromDirectory(tmpFolderPath, finalPath);
//// ZipFileCover.CreateZipFileRecursive(tmpFolderPath, finalPath, false, true);
Directory.Delete(tmpFolderPath, true);
}
#endregion
#region Public methods - Orchestration
///
/// Gets the orchestra block for.
///
/// The number of melodic tracks.
/// The number of rhythmic tracks.
/// Orchestra block.
///
/// Returns value.
///
public OrchestraBlock GetOrchestraBlockFor(byte numberOfMelodicTracks, byte numberOfRhythmicTracks, OrchestraBlock previousBlock) {
var trackCount = numberOfMelodicTracks + numberOfRhythmicTracks;
var blockCount = this.OrchestraBlocks.Count;
if (blockCount == 0) {
return null;
}
OrchestraBlock optimalBlock = null;
var maxvalue = 0;
foreach (var block in this.OrchestraBlocks) {
var value = 100 - Math.Abs(block.TrackCount - trackCount);
if (block.TrackCount < trackCount) {
value -= 20;
}
if (previousBlock != null && block.Name == previousBlock.Name) {
value -= 10;
}
value += MathSupport.RandomNatural(10);
if (value > maxvalue) {
maxvalue = value;
optimalBlock = block;
}
}
return optimalBlock;
////var idx = MathSupport.RandomNatural(blockCount);
//// return this.OrchestraBlocks[idx];
}
///
/// Gets the orchestra block for - in simple (one block) styles.
///
/// The given bar number.
/// Returns value.
[UsedImplicitly]
public OrchestraBlock GetOrchestraBlockFor(int givenBarNumber) {
if (!this.OrchestraBlocks.Any()) {
return null;
}
var orchestraBlock = (from ob in this.OrchestraBlocks
where ob.BarNumberFrom <= givenBarNumber && ob.BarNumberTo >= givenBarNumber
select ob).FirstOrDefault();
return orchestraBlock;
}
///
/// Orchestrates the musical block.
///
/// The given block.
public void OrchestrateMusicalBlock(MusicalBlock givenBlock) {
OrchestraBlock lastOBlock = null;
//// Cycle through current orchestra blocks
var orchestration = new MusicalOrchestration(givenBlock);
foreach (var block in orchestration.OrchestraBlocks) {
if (block == null) {
continue;
}
var area = new MusicalSection(block.BarNumberFrom, block.BarNumberTo, string.Empty);
//// this.blockEditor.NumberOfLines
byte numberOfMelodicLines = (byte)givenBlock.Strip.Lines.Count; //// this.NumberOfUsedLines(area);
#warning numberOfRhythmicLines
byte numberOfRhythmicLines = 0; //// this.NumberOfUsedLines(area);
//// To get ne orchestra block for the substitution
var orchestraBlock = this.GetOrchestraBlockFor(numberOfMelodicLines, numberOfRhythmicLines, lastOBlock);
lastOBlock = orchestraBlock;
if (orchestraBlock == null) {
return;
}
Orchestrate(givenBlock, area, orchestraBlock);
}
}
#endregion
#region Private static methods
///
/// Initializes a new instance of the class.
///
/// The given file path.
/// Returns value.
[UsedImplicitly]
private static MusicalOrchestration GetOrchestration(string givenFilePath) {
var style = new MusicalOrchestration();
var fileName = Path.GetFileNameWithoutExtension(givenFilePath);
if (fileName == null) {
return null;
}
style.ObjectName = fileName.Trim();
var tmpFolderPath = MusicalSettings.Singleton.Folders.GetTemporaryFolder; //// SupportFiles.GetTemporaryDirectory;
if (tmpFolderPath == null) {
return null;
}
ZipFile.ExtractToDirectory(givenFilePath, tmpFolderPath);
//// ZipFileCover.UnzipFile(givenFilePath, tmpFolderPath);
var fi = SupportFiles.LatestFile(tmpFolderPath, "*.xml");
if (fi == null) {
if (Directory.Exists(tmpFolderPath)) {
Directory.Delete(tmpFolderPath, true);
}
return null;
}
var root = XmlSupport.GetXDocRoot(Path.Combine(tmpFolderPath, "Component.xml"));
if (root != null && root.Name == "Component") {
var xstyle = root;
//// var description = XmlSupport.ReadStringAttribute(xstyle.Attribute("Description"));
//// unused var name = XmlSupport.ReadStringAttribute(xstyle.Attribute("Name"));
style.Header = new MusicalHeader(xstyle.Element("Header"));
//// this.HarmonicOrder = XmlSupport.ReadByteAttribute(xstyle.Attribute("HarmonicOrder"));
//// this.RhythmicOrder = XmlSupport.ReadByteAttribute(xstyle.Attribute("RhythmicOrder"));
}
style.LoadOrchestraBlocks(Path.Combine(tmpFolderPath, "OrchestraBlocks.xml"));
//// MusicalStyle.internalSingleton = this;
if (Directory.Exists(tmpFolderPath)) {
Directory.Delete(tmpFolderPath, true);
}
return style;
}
#endregion
#region Private methods - Load finals
///
/// Loads the orchestra model.
///
/// The file path.
private void LoadOrchestraBlocks(string filePath) {
var root = XmlSupport.GetXDocRoot(filePath);
if (root != null && root.Name == "OrchestraBlocks") {
var xbundle = root;
var xblocks = xbundle.Elements("Block");
var list = new List();
// ReSharper disable once LoopCanBeConvertedToQuery
foreach (var xblock in xblocks) {
var orchestraBlock = new OrchestraBlock(xblock);
list.Add(orchestraBlock);
}
this.OrchestraBlocks = list;
}
}
#endregion
#region Private methods - Save final
///
/// Writes the orchestra blocks.
///
/// Returns value.
private XElement WriteOrchestraBlocks() {
XElement xblocks = new XElement(
"OrchestraBlocks",
new XAttribute("Description", string.Empty));
foreach (var orchestraBlock in this.OrchestraBlocks) {
XElement xblock = orchestraBlock.GetXElement;
xblocks.Add(xblock);
}
return xblocks;
}
#endregion
}
}